package com.hjlh.aimedical.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hjlh.aimedical.common.respone.ResultModel;
import com.hjlh.aimedical.common.request.DsRequest;
import com.hjlh.aimedical.common.request.MedicalRecordRequest;
import com.hjlh.aimedical.common.respone.AskResult;
import com.hjlh.aimedical.common.respone.DsReponse;
import com.hjlh.aimedical.common.respone.MedicalRecordReponse;
import com.hjlh.aimedical.common.respone.Question;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Controller
@RequestMapping("/api/deepseek")
public class DeepSeekController {


    @RequestMapping(value = "askDs", method = RequestMethod.POST, consumes = "application/json")
    @org.springframework.web.bind.annotation.ResponseBody
    public Object askDs(@org.springframework.web.bind.annotation.RequestBody DsRequest dsRequest) throws IOException {

        String tip = "<instruction>\n" +
                "我们来模拟一段医生与患者的对话。你扮演诊所医生的角色，根据患者提供的主诉症状进行问诊，考虑到患者都是没有医学知识，请以通俗易懂的术语进行问诊。以下<example></example>是我的提供的完整示例，请按照以下步骤操作：\n" +
                "\n" +
                "1. 初始阶段：\n" +
                "   - 接收患者的主诉症状：{{patient_complaint}}\n" +
                "   - 根据主诉生成3-10个鉴别诊断方向\n" +
                "\n" +
                "2. 问诊阶段：\n" +
                "   - 针对每个鉴别诊断方向提出具体问题\n" +
                "   - 每个问题使用以下JSON格式（需要能使用com.alibaba.fastjson格式化）：\n" +
                "     [{\"question\": \"<问题文本>\",{\"Keywords\":\"<问题关键词>\"}, \"answer\": [\"<可选答案1>\", \"<可选答案2>\"]}]\n" +
                "   - 涉及身体部位的问题需列举相关部位\n" +
                "   - 涉及时间的问题需提供具体时间选项\n" +
                "   - 问题的关键词需要简练\n" +
                "   - 可选答案需要和问题进行关联\n" +
                "   - 不要提问上述已经提问过相同内容的问题\n" +
                "   - 考虑到患者都是没有医学知识，请以通俗易懂的术语进行问诊\n" +
                "\n" +
                "3. 终止条件：\n" +
                "   - 当患者说\"暂无更多病症\"时结束问诊\n" +
                "\n" +
                "4. 诊断阶段：\n" +
                "   - 给出最可能的1种诊断和2种可能的鉴别诊断\n" +
                "   - 使用以下SJON格式（需要能使用com.alibaba.fastjson格式化）返回诊断信息：\n" +
                "     {\n" +
                "       \"diagnostic_check\": [\"<检查项目1>\", \"<检查项目2>\"],\n" +
                "       \"laboratory_item\": [\"<化验项目1>\", \"<化验项目2>\"],\n" +
                "       \"medical\": \"<临时药物>\",\n" +
                "       \"diagnostic\": \"<诊疗方案>\",\n" +
                "       \"tips\": \"<注意事项>\"\n" +
                "     }\n" +
                "\n" +
                "注意事项：\n" +
                "- 所有输出必须为纯文本，不要包含任何XML标签\n" +
                "- 问题要具体且有鉴别诊断价值\n" +
                "- 给出的检查项目和化验项目应与诊断相关\n" +
                //"- 诊疗方案应是中美最新的诊疗指南\n" +
                "- 按照该疾病中国和美国最新的临床诊疗指南，给出及时的用药治疗方案，\n" +
                "- 临时药物要注明用法用量\n" +
                "- 注意事项要具体实用\n" +
                "- 每一次提问只能返回初始阶段或者诊断阶段的结果\n" +
                "- 当用户单独输入\"暂无更多病症\"时才可以进入诊断阶段，返回诊断信息\n" +
                "- 返回的报文体用到的标点符号全部都要使用半角英文符号\n" +
                "\n" +
                "<example>\n" +
                "患者主诉：\"我头痛三天了\"\n" +
                "\n" +
                "医生输出：\n" +
                "[\n" +
                "  {\"question\": \"头痛的具体部位是哪里？（可选：前额、后脑、太阳穴、全头）\",\"Keywords\":\"头痛的部位\", \"answer\": [\"头痛的具体部位是前额\",\"头痛的具体部位是后脑\",\"头痛的具体部位是太阳穴\",\"头痛的具体部位是全头\"]},\n" +
                "  {\"question\": \"头痛的性质是？(胀痛/刺痛/搏动性疼痛/紧缩感)\",\"Keywords\":\"头痛的性质\", \"answer\": [\"头痛的性质是胀痛\", \"头痛的性质是刺痛\", \"头痛的性质是搏动性疼痛\", \"头痛的性质是紧缩感\"]},\n" +
                "  {\"question\": \"疼痛是否伴随其他症状？（可选：恶心/呕吐、畏光/畏声、视力模糊、肢体无力）\",\"Keywords\":\"疼痛伴随的症状\", \"answer\": [\"疼痛伴随恶心/呕吐\",\"疼痛伴随畏光/畏声\",\"疼痛伴随视力模糊,伴随肢体无力\",\"没有其它症状了\"]},\n" +
                "  {\"question\": \"头痛持续了多长时间？（可选：小于1小时、1-24小时、1-3天、3天以上）\",\"Keywords\":\"头痛的时长\", \"answer\": [\"头痛持续了小于1小时\",\"头痛持续了1-24小时\",\"头痛持续了1-3天\",\"头痛持续了3天以上\"]},\n" +
                "  {\"question\": \"近期是否有头部外伤史或高血压病史？\",\"Keywords\":\"外伤史或高血压病史\", \"answer\": [\"否认近期有头部外伤史或高血压病史\",\"承认近期有头部外伤史或高血压病史\"]},\n" +
                "  {\"question\": \"皮肤瘙痒的具体部位是哪里？（可选：全身、四肢、躯干、面部、手足）\",\"Keywords\":\"皮肤瘙痒的部位\", \"answer\": [\"皮肤瘙痒的具体部位是全身\",\"皮肤瘙痒的具体部位是四肢\",\"皮肤瘙痒的具体部位是躯干\",\"皮肤瘙痒的具体部位是面部\",\"皮肤瘙痒的具体部位是手足\"]},\n" +
                "  {\"question\": \"是否有闪光感或视野缺损？\",\"Keywords\":\"闪光感或视野缺损\", \"answer\": [\"有闪光感或视野缺损\",\"没有闪光感或视野缺损\"]}\n" +
                "  {\"question\": \"受伤后是否进行过X光检查？\",\"Keywords\":\"X光检查\", \"answer\": [\"有进行过X光检查\",\"没有进行过X光检查\"]}\n" +
                "]\n" +
                "\n" +
                "当患者说\"暂无更多病症\"后：\n" +
                "{\n" +
                "  \"diagnostic_check\": [\"头颅CT\", \"血压监测\"],\n" +
                "  \"laboratory_item\": [\"血常规\", \"电解质\"],\n" +
                "  \"medical\": \"布洛芬200mg 必要时每6小时一次\",\n" +
                "  \"diagnostic\": \"偏头痛可能性大，需排除紧张性头痛和颅内病变\",\n" +
                "  \"tips\": \"避免劳累和强光刺激，若出现剧烈呕吐或意识改变立即就诊\"\n" +
                "}\n" +
                "</example>\n" +
                "</instruction>";
        DsRequest.Messages messages = new DsRequest.Messages();
        messages.setContent(tip);
        messages.setRole("user");
        List<DsRequest.Messages> messagesList = new ArrayList<>();
        messagesList.add(messages);
        messagesList.addAll(dsRequest.getMessages());

        dsRequest.setMessages(messagesList);
        OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(100, TimeUnit.MINUTES)
                .readTimeout(100, TimeUnit.MINUTES)
                .build();
        MediaType mediaType = MediaType.parse("application/json");
        String content = JSON.toJSONString(dsRequest);
        RequestBody body = RequestBody.create(mediaType, content);
        Request request = new Request.Builder()
                .url("https://api.deepseek.com/chat/completions")
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .addHeader("Authorization", "Bearer sk-f1e8b263255748279893110ddd201da0")
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            String responseContent = response.body().string();
            DsReponse dsReponse = JSON.parseObject(responseContent, DsReponse.class);
            String askResultText = dsReponse.getChoices().get(0).getMessage().getContent().replaceAll("```json", "").replaceAll("```", "").replaceAll("，", ",");
            log.info("askResultText ---   " + askResultText);
            if (!dsRequest.getStopFlag() && askResultText.contains("当患者说\"暂无更多病症\"后：")) {
                String[] splitContent = askResultText.split("当患者说\"暂无更多病症\"后：");
                askResultText = splitContent[0];
            } else if (askResultText.contains("病历")) {
                return askResultText;
            }
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode node = objectMapper.readTree(askResultText);

            if (dsRequest.getStopFlag() || !node.isArray()) {
                return JSON.parseObject(askResultText, AskResult.class);
            } else if (!CollectionUtils.isEmpty(dsReponse.getChoices())) {
                if (!askResultText.endsWith("]")) {
                    askResultText = askResultText.substring(0, askResultText.lastIndexOf("]") + 1);
                }
                List<Question> questions = JSONArray.parseArray(askResultText, Question.class);
                log.info(JSON.toJSONString(questions));
                return questions;

            }
            return dsReponse;
        } catch (IOException e) {
            log.error("askDs errot", e);
        } catch (JSONException e1) {
            log.error("json格式化出现错误：", e1);
        } catch (Exception e) {
            log.error("出现错误：", e);
            throw new RuntimeException(e);
        }
        return null;
    }

    @RequestMapping(value = "addRecordDS", method = RequestMethod.POST, consumes = "application/json")
    @org.springframework.web.bind.annotation.ResponseBody
    public Object createMedicalRecord(@org.springframework.web.bind.annotation.RequestBody DsRequest dsRequest) throws IOException {

        String tips = "<instruction>\n" +
                "# 核心任务\n" +
                "根据问诊对话记录生成一份标准的门诊病历\n" +
                "\n" +
                "# 输出规范\n" +
                "**必须按以下顺序和格式生成纯文本病历**：\n" +
                "\n" +
                "门诊病历：\n" +
                "\n" +
                "姓名：XXX\n" +
                "性别：男\n" +
                "年龄：20岁\n" +
                "就诊日期：XXXX年XX月XX日 \n" +
                "\n" +
                "【主诉】\n" +
                "• 直接引用患者原始描述（保留口语化表达）\n" +
                "• 示例：\"主诉：'我最近总感觉胸口发闷，尤其是爬楼梯的时候'\"\n" +
                "\n" +
                "【现病史】\n" +
                "• 总结问答过程的症状描述\n" +
                "\n" +
                "【月经史】(仅女性，没有的时候不显示该项)\n" +
                "- 初潮年龄：{{}}岁\n" +
                "- 周期规律性：规则/不规则（{{}}天/周期）\n" +
                "- 末次月经：yyyy-MM-dd\n" +
                "- 异常情况：{{痛经/经量异常}} 或 \"无\"\n" +
                "\n" +
                "【过敏史】(没有的时候不显示该项)\n" +
                "• 列出过敏药物\n" +
                "\n" +
                "【辅助检查】\n" +
                "• 影像检查：{{具体项目}}（依据ACR适用标准）\n" +
                "• 实验室检查：{{检验项目}}（注明空腹要求）\n" +
                "\n" +
                "【初步诊断】\n" +
                "初步诊断\n" +
                "\n" +
                "【处理意见】\n" +
                "处理意见\n" +
                "\n" +
                "# 质量控制\n" +
                "1. **信息完整性校验**：\n" +
                "   - 未提及的病史项标注\"未提供\"\n" +
                "   - 时间描述必须满足：事件时间 ≤ 就诊时间\n" +
                "\n" +
                "2. **格式禁令**：\n" +
                "   - 禁用任何项目符号(•/■等)，仅允许数字编号\n" +
                "   - 禁止使用斜体/粗体等文本修饰\n" +
                "   - 禁止使用英文术语（如Hypertension）\n" +
                "\n" +
                "3. **内容安全限制**：\n" +
                "   - 禁止推测未确认的疾病关联\n" +
                "   - 禁止推荐问诊阶段未讨论的检查\n" +
                "   - 禁止复制诊断阶段的治疗建议\n" +
                "\n" +
                "</instruction>";
        DsRequest.Messages messages = new DsRequest.Messages();
        messages.setContent(tips);
        messages.setRole("user");
        List<DsRequest.Messages> messagesList = new ArrayList<>();
        messagesList.add(messages);
        messagesList.addAll(dsRequest.getMessages());

        dsRequest.setMessages(messagesList);
        OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(100, TimeUnit.MINUTES)
                .readTimeout(100, TimeUnit.MINUTES)
                .build();
        MediaType mediaType = MediaType.parse("application/json");
        String content = JSON.toJSONString(dsRequest);
        RequestBody body = RequestBody.create(mediaType, content);
        Request request = new Request.Builder()
                .url("https://api.deepseek.com/chat/completions")
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .addHeader("Authorization", "Bearer sk-f1e8b263255748279893110ddd201da0")
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            String responseContent = response.body().string();
            DsReponse dsReponse = JSON.parseObject(responseContent, DsReponse.class);
            String askResultText = dsReponse.getChoices().get(0).getMessage().getContent().replaceAll("```json", "").replaceAll("```", "").replaceAll("，", ",");
            log.info("askResultText ---   " + askResultText);
            if (!dsRequest.getStopFlag() && askResultText.contains("当患者说\"暂无更多病症\"后：")) {
                String[] splitContent = askResultText.split("当患者说\"暂无更多病症\"后：");
                askResultText = splitContent[0];
            } else if (askResultText.contains("病历")) {
                return askResultText;
            }
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode node = objectMapper.readTree(askResultText);

            if (dsRequest.getStopFlag() || !node.isArray()) {
                return JSON.parseObject(askResultText, AskResult.class);
            } else if (!CollectionUtils.isEmpty(dsReponse.getChoices())) {
                if (!askResultText.endsWith("]")) {
                    askResultText = askResultText.substring(0, askResultText.lastIndexOf("]") + 1);
                }
                List<Question> questions = JSONArray.parseArray(askResultText, Question.class);
                log.info(JSON.toJSONString(questions));
                return questions;

            }
            return dsReponse;
        } catch (IOException e) {
            log.error("askDs errot", e);
        } catch (JSONException e1) {
            log.error("json格式化出现错误：", e1);
        } catch (Exception e) {
            log.error("出现错误：", e);
            throw new RuntimeException(e);
        }
        return null;
    }

    @RequestMapping(value = "saveMedicalRecord", method = RequestMethod.POST, consumes = "application/json")
    @org.springframework.web.bind.annotation.ResponseBody
    public ResultModel saveMedicalRecord(@org.springframework.web.bind.annotation.RequestBody MedicalRecordRequest medicalRecordRequest, HttpSession httpSession) throws IOException {
       /* UserModel m = (UserModel) httpSession.getAttribute("userModel");
        if (m == null) {
            return ResultModel.fail("超时，请重新登录", null);
        }*/
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        MedicalRecordReponse medicalRecordReponse = new MedicalRecordReponse();
      /*  medicalRecordReponse.setName(m.getUserName());
        medicalRecordReponse.setAge(m.getAge());
        medicalRecordReponse.setSexName(Objects.equals(m.getSex(), 1) ? "男" : "女");*/
        medicalRecordReponse.setMedical(medicalRecordRequest.getMedical());
        medicalRecordReponse.setTips(medicalRecordRequest.getTips());
        if (!CollectionUtils.isEmpty(medicalRecordRequest.getMessages())) {
            DsRequest.Messages messages = medicalRecordRequest.getMessages().get(1);
            medicalRecordReponse.setChiefComplaint(messages.getContent());
            List<DsRequest.Messages> messagesList = medicalRecordRequest.getMessages().subList(4, medicalRecordRequest.getMessages().size() - 2);
            medicalRecordReponse.setPresentIllness(messagesList.stream().map(DsRequest.Messages::getContent).collect(Collectors.toList()).stream().collect(Collectors.joining(",")));
        }
        medicalRecordReponse.setDiagnosisTime(sdf.format(new Date()));
        return ResultModel.success("生成病历成功", medicalRecordReponse);
    }


}
